/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2010 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: David Soria Parra <david.soria_parra@mayflower.de>           |
  +----------------------------------------------------------------------+
*/

/* $Id: $ */

#include "php_mysqlnd_uh.h"
#include "php_ini.h"
#include "mysqlnd_uh.h"
#include "mysqlnd_uh_classes.h"
#include "ext/standard/info.h"
#include "ext/mysqlnd/mysqlnd.h"

/* MySQLnd Plugin API */

/* Plugin ID (from mysqlnd_uh.h) */
unsigned int mysqlnd_uh_plugin_id;

/* PHP function (from mysqlnd_uh.h) */
const zend_function_entry mysqlnd_uh_functions[3];

ZEND_DECLARE_MODULE_GLOBALS(mysqlnd_uh)

#ifdef COMPILE_DL_MYSQLND_UH
ZEND_GET_MODULE(mysqlnd_uh)
#endif


/* {{{ PHP_INI */
/*
	It is handy to allow users to disable any mysqlnd plugin globally - not only for debugging :-)
	Because we register our plugin in MINIT changes to mysqlnd_uh.enabled shall be bound to
	INI_SYSTEM (and PHP restarts).
*/
PHP_INI_BEGIN()
	STD_PHP_INI_ENTRY("mysqlnd_uh.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_mysqlnd_uh_globals, mysqlnd_uh_globals)
	STD_PHP_INI_ENTRY("mysqlnd_uh.report_wrong_types", "1", PHP_INI_SYSTEM, OnUpdateBool, report_wrong_types, zend_mysqlnd_uh_globals, mysqlnd_uh_globals)
PHP_INI_END()
/* }}} */


/* {{{ php_mysqlnd_uh_globals_ctor */
static void
php_mysqlnd_uh_globals_ctor(zend_mysqlnd_uh_globals *mysqlnd_uh_globals TSRMLS_DC)
{
	mysqlnd_uh_globals->enabled = 1;
	mysqlnd_uh_globals->report_wrong_types = 1;
	mysqlnd_uh_globals->conn_user_obj = NULL;
	mysqlnd_uh_globals->conn_error_str = NULL;
	mysqlnd_uh_globals->conn_sqlstate = NULL;
	mysqlnd_uh_globals->conn_server_info = NULL;
	mysqlnd_uh_globals->conn_host_info = NULL;
	mysqlnd_uh_globals->conn_last_message = NULL;
	mysqlnd_uh_globals->conn_charset_name = NULL;
}
/* }}} */


/* {{{ PHP_MINIT_FUNCTION */
static PHP_MINIT_FUNCTION(mysqlnd_uh)
{
	ZEND_INIT_MODULE_GLOBALS(mysqlnd_uh, php_mysqlnd_uh_globals_ctor, NULL);
	/* no mysqlnd plugin requirement as such but note that we will use ini entries in register_hooks() */
	REGISTER_INI_ENTRIES();

	REGISTER_LONG_CONSTANT("MYSQLND_UH_VERSION", EXT_MYSQLND_UH_VERSION, CONST_CS | CONST_PERSISTENT);
	REGISTER_STRING_CONSTANT("MYSQLND_UH_VERSION_STR", EXT_MYSQLND_UH_VERSION_STR, CONST_CS | CONST_PERSISTENT);

	/* enum_mysqlnd_server_option */
	REGISTER_LONG_CONSTANT("MYSQLND_UH_SERVER_OPTION_MULTI_STATEMENTS_ON", MYSQL_OPTION_MULTI_STATEMENTS_ON, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_SERVER_OPTION_MULTI_STATEMENTS_OFF", MYSQL_OPTION_MULTI_STATEMENTS_OFF, CONST_CS | CONST_PERSISTENT);

	/* enum_mysqlnd_option */
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPTION_OPT_CONNECT_TIMEOUT", MYSQL_OPT_CONNECT_TIMEOUT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPTION_OPT_COMPRESS", MYSQL_OPT_COMPRESS, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPTION_OPT_NAMED_PIPE", MYSQL_OPT_NAMED_PIPE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPTION_INIT_COMMAND", MYSQL_INIT_COMMAND, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_READ_DEFAULT_FILE", MYSQL_READ_DEFAULT_FILE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_READ_DEFAULT_GROUP", MYSQL_READ_DEFAULT_GROUP, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_SET_CHARSET_DIR", MYSQL_SET_CHARSET_DIR, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_SET_CHARSET_NAME", MYSQL_SET_CHARSET_NAME, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_LOCAL_INFILE", MYSQL_OPT_LOCAL_INFILE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_PROTOCOL", MYSQL_OPT_PROTOCOL, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_SHARED_MEMORY_BASE_NAME", MYSQL_SHARED_MEMORY_BASE_NAME, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_READ_TIMEOUT", MYSQL_OPT_READ_TIMEOUT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_WRITE_TIMEOUT", MYSQL_OPT_WRITE_TIMEOUT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_USE_RESULT", MYSQL_OPT_USE_RESULT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_USE_REMOTE_CONNECTION", MYSQL_OPT_USE_REMOTE_CONNECTION, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_USE_EMBEDDED_CONNECTION", MYSQL_OPT_USE_EMBEDDED_CONNECTION, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_GUESS_CONNECTION", MYSQL_OPT_GUESS_CONNECTION, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_SET_CLIENT_IP", MYSQL_SET_CLIENT_IP, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_SECURE_AUTH", MYSQL_SECURE_AUTH, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_REPORT_DATA_TRUNCATION", MYSQL_REPORT_DATA_TRUNCATION, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_RECONNECT", MYSQL_OPT_RECONNECT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_SSL_VERIFY_SERVER_CERT", MYSQL_OPT_SSL_VERIFY_SERVER_CERT, CONST_CS | CONST_PERSISTENT);
#if PHP_MAJOR_VERSION >= 6
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE", MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_INT_AND_FLOAT_NATIVE", MYSQLND_OPT_INT_AND_FLOAT_NATIVE, CONST_CS | CONST_PERSISTENT);
#endif
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_NET_CMD_BUFFER_SIZE", MYSQLND_OPT_NET_CMD_BUFFER_SIZE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_NET_READ_BUFFER_SIZE", MYSQLND_OPT_NET_READ_BUFFER_SIZE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_SSL_KEY", MYSQLND_OPT_SSL_KEY, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_SSL_CERT", MYSQLND_OPT_SSL_CERT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_SSL_CA", MYSQLND_OPT_SSL_CA, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_SSL_CAPATH", MYSQLND_OPT_SSL_CAPATH, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_SSL_CIPHER", MYSQLND_OPT_SSL_CIPHER, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_OPT_SSL_PASSPHRASE", MYSQLND_OPT_SSL_PASSPHRASE, CONST_CS | CONST_PERSISTENT);

	/* enum_connection_close_type */
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_CLOSE_EXPLICIT", MYSQLND_CLOSE_EXPLICIT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_CLOSE_IMPLICIT", MYSQLND_CLOSE_IMPLICIT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_CLOSE_DISCONNECTED", MYSQLND_CLOSE_DISCONNECTED, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_CLOSE_LAST", MYSQLND_CLOSE_LAST, CONST_CS | CONST_PERSISTENT);

	/* php_mysqlnd_server_command */
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_SLEEP", COM_SLEEP, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_QUIT", COM_QUIT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_INIT_DB", COM_INIT_DB, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_QUERY", COM_QUERY, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_FIELD_LIST", COM_FIELD_LIST, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_CREATE_DB", COM_CREATE_DB, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_DROP_DB", COM_DROP_DB, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_REFRESH", COM_REFRESH, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_SHUTDOWN", COM_SHUTDOWN, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_STATISTICS", COM_STATISTICS, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_PROCESS_INFO", COM_PROCESS_INFO, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_CONNECT", COM_CONNECT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_PROCESS_KILL", COM_PROCESS_KILL, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_DEBUG", COM_DEBUG, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_PING", COM_PING, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_TIME", COM_TIME, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_DELAYED_INSERT", COM_DELAYED_INSERT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_CHANGE_USER", COM_CHANGE_USER, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_BINLOG_DUMP", COM_BINLOG_DUMP, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_TABLE_DUMP", COM_TABLE_DUMP, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_CONNECT_OUT", COM_CONNECT_OUT, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_REGISTER_SLAVED", COM_REGISTER_SLAVE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_STMT_PREPARE", COM_STMT_PREPARE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_STMT_EXECUTE", COM_STMT_EXECUTE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_STMT_SEND_LONG_DATA", COM_STMT_SEND_LONG_DATA, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_STMT_CLOSE", COM_STMT_CLOSE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_STMT_RESET", COM_STMT_RESET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_SET_OPTION", COM_SET_OPTION, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_STMT_FETCH", COM_STMT_FETCH, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_DAEMON", COM_DAEMON, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_COM_END", COM_END, CONST_CS | CONST_PERSISTENT);

	/* enum mysqlnd_packet_type */
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_GREET_PACKET", PROT_GREET_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_AUTH_PACKET", PROT_AUTH_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_OK_PACKET", PROT_OK_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_EOF_PACKET", PROT_EOF_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_CMD_PACKET", PROT_CMD_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_RSET_HEADER_PACKET", PROT_RSET_HEADER_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_RSET_FLD_PACKET", PROT_RSET_FLD_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_ROW_PACKET", PROT_ROW_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_STATS_PACKET", PROT_STATS_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PREPARE_RESP_PACKET", PROT_PREPARE_RESP_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_CHG_USER_RESP_PACKET", PROT_CHG_USER_RESP_PACKET, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("MYSQLND_UH_MYSQLND_PROT_LAST", PROT_LAST, CONST_CS | CONST_PERSISTENT);

	/*
		We do not need to set a destructor here. Our resource is bound to a mysqlnd connection.
		If the mysqlnd connection, which itself is a resource, is to be destroyed, we will be told
		beforehand through the mysqlnd connection method close() and end_psession() callbacks.
		It should do no harm to set a dtor callback, though, it is not needed as we handle
		destruction through close()/end_psession(). Also, our resource is nothing but
		a userland pointer to the mysqlnd connection to which it is bound - what would you want
		to destruct and clean up...
		For ease of use we do no use persistent resources even if the mysqlnd connection is persistent.
		That's an area of future tuning work.
	*/
	le_mysqlnd_uh_mysqlnd = zend_register_list_destructors_ex(NULL, NULL, MYSQLND_UH_RES_MYSQLND_NAME, module_number);


	/*
		Hackish as hackish can be... some default class implementations (e.h. MySQLndUhConnection)
		do call	mysqlnd default function handler and need to be able to bubble up the
		return value from the mysqlnd default function to our handler. Its like this:

		 plain C our_mysqlnd_handler.somefunc()
		   --> calls PHP_METHOD MySQLndUhConnection::somefunc()
		   --> calls plain C mysqlnd function handler  mysqlnd.somefunc()
		   <-- plain C mysqlnd function handler returns type that cannot be represented as zval (e.g. MYSQLND_RES*)
		   <-- MySQLndUhConnection::somefunc() return resource wrapping return value (e.g. MYSQLND_RES)
		our_mysqlnd_handler.somefunc() extracts resource

		I said its ugly... Here we go with a couple of resources which we will use only internally.
	*/
	le_mysqlnd_uh_mysqlnd_res 	= zend_register_list_destructors_ex(NULL, NULL, MYSQLND_UH_RES_MYSQLND_RESULT_NAME, module_number);
	le_mysqlnd_uh_mysqlnd_stmt 	= zend_register_list_destructors_ex(NULL, NULL, MYSQLND_UH_RES_MYSQLND_STMT_NAME, module_number);

	/* userland classes - see mysqlnd_uh_classes.c */
	mysqlnd_uh_minit_register_classes(TSRMLS_C);

	/* MySQLnd Plugin related - see mysqlnd_uh.c */
	mysqlnd_uh_minit_register_hooks(TSRMLS_C);

	return SUCCESS;
}
/* }}} */


/* {{{ PHP_MSHUTDOWN_FUNCTION */
static PHP_MSHUTDOWN_FUNCTION(mysqlnd_uh)
{
	UNREGISTER_INI_ENTRIES();

	return SUCCESS;
}
/* }}} */

/* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(mysqlnd_uh) {
	MYSQLND_UH_G(conn_error_str) 	= safe_emalloc(1, MYSQLND_UH_ERRMSG_SIZE, 1);
	MYSQLND_UH_G(conn_sqlstate) 	= safe_emalloc(1, MYSQLND_UH_SQLSTATE_LENGTH, 1);
	MYSQLND_UH_G(conn_server_info)	= safe_emalloc(1, MYSQLND_UH_SERVER_INFO_LENGTH, 1);
	MYSQLND_UH_G(conn_host_info)	= safe_emalloc(1, MYSQLND_UH_HOST_INFO_LENGTH, 1);
	MYSQLND_UH_G(conn_last_message)	= safe_emalloc(1, MYSQLND_UH_LAST_MESSAGE_LENGTH, 1);
	MYSQLND_UH_G(conn_charset_name)	= safe_emalloc(1, MYSQLND_UH_CHARSET_NAME_LENGTH, 1);

	return SUCCESS;
}
/* }}} */

/* {{{ PHP_RSHUTDOWN_FUNCTION  */
PHP_RSHUTDOWN_FUNCTION(mysqlnd_uh) {

	if (MYSQLND_UH_G(conn_user_obj)) {
		zval_ptr_dtor(&(MYSQLND_UH_G(conn_user_obj)));
		MYSQLND_UH_G(conn_user_obj) = NULL;
	}
	efree(MYSQLND_UH_G(conn_charset_name));
	efree(MYSQLND_UH_G(conn_last_message));
	efree(MYSQLND_UH_G(conn_host_info));
	efree(MYSQLND_UH_G(conn_server_info));
	efree(MYSQLND_UH_G(conn_sqlstate));
	efree(MYSQLND_UH_G(conn_error_str));

	return SUCCESS;
}
 /* }}} */

/* {{{ PHP_MINFO_FUNCTION */
static PHP_MINFO_FUNCTION(mysqlnd_uh)
{
	char buf[64];

	php_info_print_table_start();
	php_info_print_table_header(2, "mysqlnd_uh support", "enabled");

	snprintf(buf, sizeof(buf), "%s (%d)", EXT_MYSQLND_UH_VERSION_STR, EXT_MYSQLND_UH_VERSION);
	php_info_print_table_row(2, "MySQLnd User Handler (mysqlnd_uh)", buf);
	snprintf(buf, sizeof(buf), "%d", mysqlnd_uh_plugin_id);
	php_info_print_table_row(2, "MySQLnd Plugin ID", buf);
	php_info_print_table_end();

	DISPLAY_INI_ENTRIES();
}
/* }}} */


static const zend_module_dep mysqlnd_uh_deps[] = {
	ZEND_MOD_REQUIRED("mysqlnd")
	ZEND_MOD_REQUIRED("mysqli")
	{NULL, NULL, NULL}
};


/* {{{ mysqlnd_uh_module_entry */
zend_module_entry mysqlnd_uh_module_entry = {
	STANDARD_MODULE_HEADER_EX,
	NULL,
	mysqlnd_uh_deps,
	EXT_MYSQLND_UH_NAME,
	mysqlnd_uh_functions,
	PHP_MINIT(mysqlnd_uh),
	PHP_MSHUTDOWN(mysqlnd_uh),
	PHP_RINIT(mysqlnd_uh),
	PHP_RSHUTDOWN(mysqlnd_uh),
	PHP_MINFO(mysqlnd_uh),
	EXT_MYSQLND_UH_VERSION_STR,
	PHP_MODULE_GLOBALS(mysqlnd_uh),
	NULL,
	NULL,
	NULL,
	STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
